﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_MATH_H
#define _UXS_MATH_H

#pragma once

#include "../CompileTime/Constants.h"
#include "../Containers/TStaticArray.h"
#include "../Types/MemFunc.h"
#include "FastMath.h"
#include "TVec.h"

namespace UX_STL
{
namespace UXMath
{

//-------------------------------------------------------------------
//	Trigonometry
	

	//
	// Degrees to Radians
	//
	
	template <typename T>
	inline T DTR(const T& x)
	{
		return ( x * Pi<T>() / T(180.0) );
	}

	template <typename T, usize I>
	inline TVec<T,I>  DTR(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = DTR( x[i] );
		return ret;
	}



	//
	// Radians to Degrees
	//

	template <typename T>
	inline T RTD(const T& x)
	{
		return ( x * T(180.0) / Pi<T>() );
	}

	template <typename T, usize I>
	inline TVec<T,I>  RTD(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = RTD( x[i] );
		return ret;
	}



	//
	// To Near Supported float types
	//

	namespace _math_hidden_
	{
		template <bool b64>		struct _ToNearFloat			{ typedef float  type; };
		template <>				struct _ToNearFloat<true>	{ typedef double type; };

		template <typename T>
		struct ToNearFloat
		{
			typedef typename _ToNearFloat< sizeof(T) >= sizeof(double) >::type	type;
		};
	}
	


	//
	// Check Angles In Radians
	//

	namespace _math_hidden_
	{
		template <typename T>
		inline static void _CheckAngle (T MinAngle, T MaxAngle, T angle)
		{
			ASSERT( angle >= MinAngle and angle <= MaxAngle );
		}
	}




	//
	// Sin, Cos, SinCos
	//

	template <typename T>
	inline T  Sin(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::sin( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Sin(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Sin( x[i] );
		return ret;
	}


	template <typename T>
	inline T  Cos(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::cos( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Cos(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Cos( x[i] );
		return ret;
	}


	template <typename T, typename S, typename C>
	inline void SinCos(const T& x, OUT S& s, OUT C& c)
	{
		s = Sin( x );
		c = Cos( x );
	}


	template <typename T, usize I, typename S, typename C>
	inline void  SinCos(const TVec<T,I> &x, OUT TVec<S,I> &s, OUT TVec<C,I> &c)
	{
		FOR( i, x )	SinCos( x[i], s[i], c[i] );
	}


	template <typename T>
	inline TVec<T,2>  SinCos(const T& x)
	{
		TVec<T,2>	ret;
		SinCos( x, ret.x, ret.y );
		return ret;
	}




	//
	// ASin, ACos, ASinCos
	//
	
	template <typename T>
	inline T  ASin(const T& x)
	{
		ASSERT( x >= T(-1) and x <= T(1) );
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::asin( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ASin(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ASin( x[i] );
		return ret;
	}


	template <typename T>
	inline T  ACos(const T& x)
	{
		ASSERT( x >= T(-1) and x <= T(1) );
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::acos( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ACos(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ACos( x[i] );
		return ret;
	}

	
	template <typename T, typename S, typename C>
	inline void ASinCos(const T& x, OUT S& s, OUT C& c)
	{
		s = ASin( x );
		c = ACos( x );
	}
	

	template <typename T, usize I, typename S, typename C>
	inline void  ASinCos(const TVec<T,I> &x, OUT TVec<S,I> &s, OUT TVec<C,I> &c)
	{
		FOR( i, x )	ASinCos( x[i], s[i], c[i] );
	}


	template <typename T>
	inline TVec<T,2>  ASinCos(const T& x)
	{
		TVec<T,2>	ret;
		ASinCos( x, ret.x, ret.y );
		return ret;
	}



	//
	// SinH, CosH, SinCosH
	//

	template <typename T>
	inline T  SinH(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::sinh( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  SinH(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SinH( x[i] );
		return ret;
	}


	template <typename T>
	inline T  CosH(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::cosh( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  CosH(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = CosH( x[i] );
		return ret;
	}


	template <typename T, typename S, typename C>
	inline void  SinCosH(const T& x, OUT S& s, OUT C& c)
	{
		s = SinH( x );
		c = CosH( x );
	}

	
	template <typename T, usize I, typename S, typename C>
	inline void  SinCosH(const TVec<T,I> &x, OUT TVec<S,I> &s, OUT TVec<C,I> &c)
	{
		FOR( i, x )	SinCosH( x[i], s[i], c[i] );
	}


	template <typename T>
	inline TVec<T,2>  SinCosH(const T& x)
	{
		TVec<T,2>	ret;
		SinCosH( x, ret.x, ret.y );
		return ret;
	}



	//
	// ASinH, ACosH, ASinCosH
	//

	template <typename T>
	inline T  ASinH(const T& x)
	{
		return SignOrZero( x ) * Ln( x + Sqrt( (x*x) + T(1) ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ASinH(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ASinH( x[i] );
		return ret;
	}


	template <typename T>
	inline T  ACosH(const T& x)
	{
		return Ln( x + Sqrt( (x*x) - T(1) ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ACosH(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ACosH( x[i] );
		return ret;
	}


	template <typename T, typename S, typename C>
	inline void  ASinCosH(const T& x, OUT S& s, OUT C& c)
	{
		s = ASinH( x );
		c = ACosH( x );
	}

	
	template <typename T, usize I, typename S, typename C>
	inline void  ASinCosH(const TVec<T,I> &x, OUT TVec<S,I> &s, OUT TVec<C,I> &c)
	{
		FOR( i, x )	ASinCosH( x[i], s[i], c[i] );
	}


	template <typename T>
	inline TVec<T,2>  ASinCosH(const T& x)
	{
		TVec<T,2>	ret;
		ASinCosH( x, ret.x, ret.y );
		return ret;
	}



	//
	// Tan, CoTan, ATan, ACoTan
	//

	template <typename T>
	inline T  Tan(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::tan( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Tan(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Tan( x[i] );
		return ret;
	}


	template <typename T>
	inline T  CoTan(const T& x)
	{/*
		const T	 tmp = Tan( x );
		ASSUME( tmp != T(0) and "division by zero" );
		return T(1) / tmp;
		*/
		return SafeDiv( T(1), Tan( x ), T(0) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  CoTan(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = CoTan( x[i] );
		return ret;
	}


	template <typename T>
	inline T  ATan(const T& y_over_x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::atan( float_t( y_over_x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ATan(const TVec<T,I> &y_over_x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ATan( y_over_x[i] );
		return ret;
	}


	template <typename T>
	inline T  ATan(const T& y, const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::atan2( float_t( y ), float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ATan(const TVec<T,I> &y, const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ATan( y[i], x[i] );
		return ret;
	}


	template <typename T>
	inline T  ACoTan(const T& x)
	{/*
		const T	 tmp = ATan( x );
		ASSUME( tmp != T(0) and "division by zero" );
		return T(1) / tmp;*/
		return SafeDiv( T(1), ATan( x ), T(0) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ACoTan(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ACoTan( x[i] );
		return ret;
	}


	template <typename T>
	inline T  ATanH(const T& a)
	{
		const T	 x( a );

		if ( x == T(1) )	return Infinity<T>();	else
		if ( x >  T(1) )	return NaN<T>();		else
		
		return Ln( (T(1) + x) / (T(1) - x) ) / T(2);
	}


	template <typename T, usize I>
	inline TVec<T,I>  ATanH(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ATanH( x[i] );
		return ret;
	}


	template <typename T>
	inline T  ACoTanH(const T& x)
	{/*
		const T  tmp = ATanH( x );
		ASSUME( tmp != T(0) and "division by zero" );
		return T(1) / tmp;*/
		return SafeDiv( T(1), ATanH( x ), T(0) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ACoTanH(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ACoTanH( x[i] );
		return ret;
	}



//-------------------------------------------------------------------
//	Operation with sign


	//
	// Abs
	//
	
	namespace _math_hidden_
	{
		template <bool S, bool I>
		struct _Abs_impl
		{
			template <typename T>	static T abs(const T& val);
		};

		template <>
		struct _Abs_impl<true,true>
		{
			template <typename T>	static T abs(const T& val)		{ return (val < 0) ? -val : val; }
		};

		template <>
		struct _Abs_impl<false,true>
		{
			template <typename T>	static T abs(const T& val)		{ return val; }
		};

		template <>
		struct _Abs_impl<false,false>
		{
			template <typename T>	static T abs(const T& val)		{ return val; }
		};

		template <>
		struct _Abs_impl<true,false>
		{
			template <typename T>	static T abs(const T& val)
			{
				typedef typename TypeInfo< T >::Similar_UInt	int_t;
			
				static const int_t	mask = ~( int_t(1) << TypeInfo< T >::SignBit() );

				T	ret( val );
				ReferenceCast< int_t >( ret ) &= mask;
				return ret;
			}
		};
		
		template <typename T>
		struct _Abs
		{
			static T abs(const T& val)
			{
				return _Abs_impl< TypeDescriptor::IsSigned<T>::value, TypeDescriptor::IsInteger<T>::value >::template abs( val );
			}
		};
	}
	
	template <typename T>
	inline T Abs(const T& val)
	{
		return _math_hidden_::_Abs<T>::abs( val );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Abs(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Abs( x[i] );
		return ret;
	}



	//
	// Sign, SignOrZero
	//

	// 1 or -1
	template <typename T>
	inline int Sign(const T& x)
	{
		return ( x >= T(0) ? 1 : -1 );
	}


	template <typename T, usize I>
	inline TVec<int,I>  Sign(const TVec<T,I> &x)
	{
		TVec<int,I>	ret;
		FOR( i, ret )	ret[i] = Sign<T>( x[i] );
		return ret;
	}


	// 1 or 0 or -1
	template <typename T>
	inline int SignOrZero(const T& x)
	{
		return ( x > T(0) ) - ( x < T(0) );
	}


	template <typename T, usize I>
	inline TVec<int,I>  SignOrZero(const TVec<T,I> &x)
	{
		TVec<int,I>	ret;
		FOR( i, ret )	ret[i] = SignOrZero( x[i] );
		return ret;
	}



	//
	// Set or Reset Sign
	//

	namespace _math_hidden_
	{
		template <bool bFloat, bool bSigned>
		struct _SetSign_impl
		{
			template <typename T>
			static T setsign(const T& x, bool s);
		};

		template <>
		struct _SetSign_impl<true,true>
		{
			template <typename T>
			static T setsign(const T& x, bool s)
			{
				typedef typename TypeInfo<T>::Similar_UInt	uint_t;
				
				const uint	u_sign_bit	= TypeInfo<T>::SignBit();

				T	ret(x);
				ReferenceCast<uint_t>( ret ) &= ~( uint_t(1) << u_sign_bit );
				ReferenceCast<uint_t>( ret ) |=  ( uint_t(s) << u_sign_bit );
				return ret;
			}
		};

		template <>
		struct _SetSign_impl<false,true>
		{
			template <typename T>
			static T setsign(const T& x, bool s)
			{
				if ( (  s and x > (T)0 ) or
					 ( not s and x < (T)0 ) )
				{
					return -x;
				}
				return x;
			}
		};

		template <>
		struct _SetSign_impl<true,false>
		{
			template <typename T>
			static T setsign(const T& x, bool s)
			{
				ASSUME( not s and "value already unsigned" );
				return x;
			}
		};

		template <>
		struct _SetSign_impl<false,false>
		{
			template <typename T>
			static T setsign(const T& x, bool s)
			{
				ASSUME( not s and "value already unsigned" );
				return x;
			}
		};

		template <typename T>
		struct _SetSign
		{
			static T setsign(const T& x, bool s)
			{
				return _SetSign_impl< TypeDescriptor::IsFloat<T>::value,
									  TypeDescriptor::IsSigned<T>::value >::setsign( x, s );
			}
		};
	}

	template <typename T>
	inline T SetSign(const T &x, bool bSign)
	{
		return _math_hidden_::_SetSign<T>::setsign( x, bSign );
	}


	template <typename T, usize I>
	inline TVec<T,I>  SetSign(const TVec<T,I> &x, bool bSign)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SetSign( x[i], bSign );
		return ret;
	}


	template <typename T, usize I>
	inline TVec<T,I>  SetSign(const TVec<T,I> &x, const TVec<bool,I> &vSign)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SetSign( x[i], vSign[i] );
		return ret;
	}



	//
	// Copy Sign
	//

	namespace _math_hidden_
	{
		template <bool bFloat, bool bSigned>
		struct _CopySign_impl
		{
			template <typename T>
			static T copysign(const T& x, const T& s);
		};

		template <>
		struct _CopySign_impl<true,true>
		{
			template <typename T>
			static T copysign(const T& x, const T& s)
			{
				typedef typename TypeInfo<T>::Similar_UInt	uint_t;
				
				const uint_t	u_sign_mask	= uint_t(1) << TypeInfo<T>::SignBit();

				T	ret(x);
				ReferenceCast<uint_t>( ret ) &= ~u_sign_mask;
				ReferenceCast<uint_t>( ret ) |=  ReferenceCast<uint_t>( s ) & u_sign_mask;
				return ret;
			}
		};

		template <>
		struct _CopySign_impl<false,true>
		{	
			template <typename T>
			static T copysign(const T& x, const T& s)
			{
				if ( ( s >= T(0) and x >= T(0) ) or
					 ( s <= T(0) and x <= T(0) ) )
				{
					return x;
				}
				return -x;
			}
		};

		template <>
		struct _CopySign_impl<true,false>
		{
			template <typename T>
			static T copysign(const T& x, const T& s)
			{
				return x;
			}
		};

		template <>
		struct _CopySign_impl<false,false>
		{
			template <typename T>
			static T copysign(const T& x, const T& s)
			{
				return x;
			}
		};

		template <typename T>
		struct _CopySign
		{
			static T copysign(const T& x, const T& s)
			{
				return _CopySign_impl< TypeDescriptor::IsFloat<T>::value,
									   TypeDescriptor::IsSigned<T>::value >::copysign( x, s );
			}
		};
	}
	
	template <typename T>
	inline T CopySign(const T& from, const T& to)
	{
		return _math_hidden_::_CopySign<T>::copysign( to, from );
	}


	template <typename T, usize I>
	inline TVec<T,I>  CopySign(const TVec<T,I> &from, const TVec<T,I> &to)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = CopySign( from[i], to[i] );
		return ret;
	}



//-------------------------------------------------------------------
//	Compare operations


	//
	// IsZero
	//

	namespace _math_hidden_
	{
		template <bool I>
		struct _IsZero_impl
		{
			template <typename T>	static bool is_zero(const T& x);
		};

		template <>
		struct _IsZero_impl<true>
		{
			template <typename T>	static bool is_zero(const T& x)		{ return x == T(0); }
		};

		template <>
		struct _IsZero_impl<false>
		{
			template <typename T>	static bool is_zero(const T& x)		{ return Abs(x) <= TypeInfo<T>::Epsilon(); }
		};

		template <typename T>
		struct _IsZero
		{
			static bool is_zero(const T& x)
			{
				return _IsZero_impl< TypeDescriptor::IsInteger<T>::value >::is_zero( x );
			}
		};
	}

	template <typename T>
	inline bool IsZero(const T& x)
	{
		return _math_hidden_::_IsZero<T>::is_zero( x );
	}

	template <>
	inline bool IsZero(const bool& x)
	{
		return not x;
	}

	
	template <typename T, usize I>
	inline bool IsZero(const TVec<T,I>& v)
	{
		return All( v.IsZero() );
	}


	template <typename T>
	inline bool IsNotZero(const T& val)
	{
		return not IsZero( val );
	}

	template <>
	inline bool IsNotZero(const bool& x)
	{
		return x;
	}
	


	//
	// Equals
	//

	namespace _math_hidden_
	{
		// integer
		template <bool F>
		struct _Equals_impl
		{
			template <typename T>
			static bool eq(const T& a, const T& b)
			{ 
				return a == b;
			}

			template <typename T>
			static bool eqa(const T& a, const T& b, uint ac)
			{
				typedef typename TypeInfo<T>::Similar_Unsigned	uint_t;
				return uint_t( Abs( a - b ) ) <= ( uint_t(1) << ac );
			}
		};

		template <typename T>	struct _FloatAccuracy			{ static const uint	value = CompileTime::SizeOf<T>::bits / 3; };
		template <>				struct _FloatAccuracy<double>	{ static const uint	value = CompileTime::SizeOf<double>::bits * 2 / 3; };

		
		// float
		template <>
		struct _Equals_impl<true>
		{
			template <typename T>
			static bool eq(const T& a, const T& b)
			{
				return eqa( a, b, _FloatAccuracy<T>::value );
				//return (a + TypeInfo<T>::Epsilon() >= b) and (a - TypeInfo<T>::Epsilon() <= b);
			}

			template <typename T>
			static bool eqa(const T& a, const T& b, uint ac)
			{
				typedef typename TypeInfo<T>::Similar_Int	int_t;
				typedef typename TypeInfo<T>::Similar_UInt	uint_t;

				int_t	i_a = ReferenceCast<int_t>(a);
				int_t	i_b	= ReferenceCast<int_t>(b);

				if ( i_a < int_t(0) )	i_a = TypeInfo<int_t>::Min() - i_a;
				if ( i_b < int_t(0) )	i_b = TypeInfo<int_t>::Min() - i_b;

				uint_t	diff = (uint_t)Abs( i_a - i_b );

				return ( diff <= ( uint_t(1) << ac ) );
			}
		};
		
		template <typename T>
		struct _Equals
		{
			static bool eq(const T& a, const T& b)
			{
				return _Equals_impl< TypeDescriptor::IsFloat<T>::value >::eq( a, b );
			}

			static bool eqa(const T& a, const T& b, uint ac)
			{
				return _Equals_impl< TypeDescriptor::IsFloat<T>::value >::eqa( a, b, ac );
			}
		};
	}

	template <typename T>
	inline bool Equals(const T& a, const T& b)
	{
		return _math_hidden_::_Equals<T>::eq( a, b );
	}


	template <typename T, usize I>
	inline TVec<bool,I>  Equals(const TVec<T,I> &a, const TVec<T,I> &b)
	{
		TVec<bool,I>	ret;
		FOR( i, ret )	ret[i] = Equals( a[i], b[i] );
		return ret;
	}


	template <typename T>
	inline bool Equals(const T& a, const T& b, /*Bits*/uint accuracy)
	{
		return _math_hidden_::_Equals<T>::eqa( a, b, accuracy );
	}


	template <typename T, usize I>
	inline TVec<bool,I>  Equals(const TVec<T,I> &a, const TVec<T,I> &b, /*Bits*/uint accuracy)
	{
		TVec<bool,I>	ret;
		FOR( i, ret )	ret[i] = Equals( a[i], b[i], accuracy );
		return ret;
	}



	//
	// MediumValue
	//
	
	template <typename A, typename B>
	inline typename TypeDescriptor::MainType<A,B>::type  MediumValue (const A& a, const B& b)
	{
		// TODO: for integer types cast to float
		return (a + b) / 2;
	}


	template <typename A, typename B, usize I>
	inline TVec< typename TypeDescriptor::MainType<A,B>::type, I >  MediumValue (const TVec<A,I>& a, const TVec<B,I>& b)
	{
		TVec< typename TypeDescriptor::MainType<A,B>::type, I >	ret;
		FOR( i, ret )	ret[i] = MediumValue( a[i], b[i] );
		return ret;
	}



	//
	// Clamp (ClampInnerRange)
	//
	
	template <typename A, typename B, typename C>
	inline typename TypeDescriptor::MainType3<A,B,C>::type  Clamp (const A& tValue, const B& tMin, const C& tMax)
	{
		return Min( tMax, Max( tValue, tMin ) );
	}

	
	template <typename A, typename B, typename C, usize I>
	inline TVec< typename TypeDescriptor::MainType3<A,B,C>::type, I >  Clamp (const TVec<A,I>& tValue, const TVec<B,I>& tMin, const TVec<C,I>& tMax)
	{
		TVec< typename TypeDescriptor::MainType3<A,B,C>::type, I >	ret;
		FOR( i, ret )	ret[i] = Clamp( tValue[i], tMin[i], tMax[i] );
		return ret;
	}

	
	template <typename A, typename B, typename C, usize I>
	inline TVec<A,I>  Clamp(const TVec<A,I>& tValue, const B& tMin, const C& tMax)
	{
		TVec<A,I>	ret;
		FOR( i, ret )	ret[i] = Clamp( tValue[i], tMin, tMax );
		return ret;
	}



	//
	// ClampOut (ClampOuterRange)
	//
	
	template <typename A, typename B, typename C>
	inline typename TypeDescriptor::MainType3<A,B,C>::type ClampOut(const A& tValue, const B& tLeft, const C& tRight)
	{
		typedef typename TypeDescriptor::MainType3<A,B,C>::type	T;

		const T	middle = MediumValue( tLeft, tRight );

		return	( tValue >= middle ? 
				( tValue <= tRight ?  tRight : tValue ) :
				( tValue >= tLeft  ?  tLeft  : tValue ) );
	}
	

	template <typename A, typename B, typename C, usize I>
	inline TVec< typename TypeDescriptor::MainType3<A,B,C>::type, I >  ClampOut(const TVec<A,I>& tValue, const TVec<B,I>& tLeft, const TVec<C,I>& tRight)
	{
		TVec< typename TypeDescriptor::MainType3<A,B,C>::type, I >	ret;
		FOR( i, ret )	ret[i] = ClampOut( tValue[i], tLeft[i], tRight[i] );
		return ret;
	}
	
	
	template <typename A, typename B, typename C, usize I>
	inline TVec<A,I>  ClampOut(const TVec<A,I>& tValue, const B& tLeft, const C& tRight)
	{
		TVec<A,I>	ret;
		FOR( i, ret )	ret[i] = ClampOut( tValue[i], tLeft, tRight );
		return ret;
	}



	//
	// All, Any, Most
	//
	
	namespace _math_hidden_
	{
		template <usize C>
		struct _AnyAllMost_impl
		{
			template <typename T, usize I>	static bool Any (const UXMath::TVec<T,I> &v)	{ return _AnyAllMost_impl<C-1>::Any( v ) | UXMath::IsNotZero( v[C] ); }
			template <typename T, usize I>	static bool All (const UXMath::TVec<T,I> &v)	{ return _AnyAllMost_impl<C-1>::All( v ) & UXMath::IsNotZero( v[C] ); }
			template <typename T, usize I>	static uint Most (const UXMath::TVec<T,I> &v)	{ return _AnyAllMost_impl<C-1>::Most( v ) + (uint)UXMath::IsNotZero( v[C] ); }
		};
		
		template <>
		struct _AnyAllMost_impl<0>
		{
			template <typename T, usize I>	static bool Any (const UXMath::TVec<T,I> &v)	{ return UXMath::IsNotZero( v[0] ); }
			template <typename T, usize I>	static bool All (const UXMath::TVec<T,I> &v)	{ return UXMath::IsNotZero( v[0] ); }
			template <typename T, usize I>	static uint Most (const UXMath::TVec<T,I> &v)	{ return (uint) UXMath::IsNotZero( v[0] ); }
		};

		template <typename T, usize I>
		struct _AnyAllMost
		{
			static bool  All(const UXMath::TVec<T,I> &v)	{ return _AnyAllMost_impl<I-1>::All( v ); }
			static bool  Any(const UXMath::TVec<T,I> &v)	{ return _AnyAllMost_impl<I-1>::Any( v ); }
			static bool  Most(const UXMath::TVec<T,I> &v)	{ return _AnyAllMost_impl<I-1>::Most( v )*2 >= I; }	// 1 of 2; 2 of 3; 2 of 4;
		};
	}
	
	template <typename T>
	inline bool All (const T& x)
	{
		return IsNotZero( x );
	}


	template <typename T, usize I>
	inline bool All (const TVec<T,I> &x)
	{
		return _math_hidden_::_AnyAllMost<T,I>::All( x );
	}

	
	template <typename T>
	inline bool Any (const T& x)
	{
		return IsNotZero( x );
	}


	template <typename T, usize I>
	inline bool Any (const TVec<T,I> &x)
	{
		return _math_hidden_::_AnyAllMost<T,I>::Any( x );
	}

	
	template <typename T>
	inline bool Most (const T& x)
	{
		return IsNotZero( x );
	}


	template <typename T, usize I>
	inline bool Most (const TVec<T,I> &x)
	{
		return _math_hidden_::_AnyAllMost<T,I>::Most( x );
	}

	

	//
	// Max
	//

	template <typename A, typename B>
	inline typename TypeDescriptor::MainType<A,B>::type  Max (const A& a, const B& b)
	{
		return ( a > b ? a : b );
	}

	template <typename A, typename B, usize I>
	inline TVec< typename TypeDescriptor::MainType<A,B>::type, I >  Max (const TVec<A,I> &a, const TVec<B,I> &b)
	{
		TVec< typename TypeDescriptor::MainType<A,B>::type, I >	ret;
		FOR( i, ret )	ret[i] = Max( a[i], b[i] );
		return ret;
	}
	
	template <typename A, typename B, typename C>
	inline typename TypeDescriptor::MainType3<A,B,C>::type  Max (const A& a, const B& b, const C& c)
	{
		return Max( Max( a, b ), c );
	}
	
	template <typename A, typename B, typename C, typename D>
	inline typename TypeDescriptor::MainType4<A,B,C,B>::type  Max (const A& a, const B& b, const C& c, const D& d)
	{
		return Max( Max( a, b ), Max( c, d ) );
	}
	

	//
	// Min
	//

	template <typename A, typename B>
	inline typename TypeDescriptor::MainType<A,B>::type  Min (const A& a, const B& b)
	{
		return ( a > b ? b : a );
	}

	template <typename A, typename B, usize I>
	inline TVec< typename TypeDescriptor::MainType<A,B>::type, I >  Min (const TVec<A,I> &a, const TVec<B,I> &b)
	{
		TVec< typename TypeDescriptor::MainType<A,B>::type, I >	ret;
		FOR( i, ret )	ret[i] = Min( a[i], b[i] );
		return ret;
	}
	
	template <typename A, typename B, typename C>
	inline typename TypeDescriptor::MainType3<A,B,C>::type  Min (const A& a, const B& b, const C& c)
	{
		return ( Most( a > b ) ? Min( b, c ) : Min( a, c ) );
	}
	
	template <typename A, typename B, typename C, typename D>
	inline typename TypeDescriptor::MainType4<A,B,C,D>::type  Min (const A& a, const B& b, const C& c, const D& d)
	{
		return Min( Min( a, b ), Min( c, d ) );
	}

	
	//
	// MinAbs
	//

	template <typename A, typename B>
	inline typename TypeDescriptor::MainType<A,B>::type  MinAbs (const A& a, const B& b)
	{
		return ( Abs(a) > Abs(b) ? b : a );
	}

	template <typename A, typename B, usize I>
	inline TVec< typename TypeDescriptor::MainType<A,B>::type, I >  MinAbs (const TVec<A,I> &a, const TVec<B,I> &b)
	{
		TVec< typename TypeDescriptor::MainType<A,B>::type, I >	ret;
		FOR( i, ret )	ret[i] = MinAbs( a[i], b[i] );
		return ret;
	}

	
	//
	// MaxAbs
	//

	template <typename A, typename B>
	inline typename TypeDescriptor::MainType<A,B>::type MaxAbs (const A& a, const B& b)
	{
		return ( Most( Abs(a) > Abs(b) ) ? a : b );
	}

	template <typename A, typename B, usize I>
	inline TVec< typename TypeDescriptor::MainType<A,B>::type, I >  MaxAbs (const TVec<A,I> &a, const TVec<B,I> &b)
	{
		TVec< typename TypeDescriptor::MainType<A,B>::type, I >	ret;
		FOR( i, ret )	ret[i] = MaxAbs( a[i], b[i] );
		return ret;
	}

	
	//
	// MinMax
	//

	template <typename A, typename B>
	inline void	MinMax (OUT typename TypeDescriptor::MainType<A,B>::type& tMin,
						OUT typename TypeDescriptor::MainType<A,B>::type& tMax,
						const A& a, const B& b)
	{
		const bool	res = ( a > b );
		tMin = res ? b : a;
		tMax = res ? a : b;
	}

	template <typename A, typename B, usize I>
	inline void	MinMax (OUT TVec< typename TypeDescriptor::MainType<A,B>::type, I >& tMin,
						OUT TVec< typename TypeDescriptor::MainType<A,B>::type, I >& tMax,
						const TVec<A,I>& a, const TVec<B,I>& b)
	{
		FOR( i, a ) {
			MinMax( tMin[i], tMax[i], a[i], b[i] );
		}
	}

	
	//
	// MinMag
	//

	template <typename A, typename B>
	inline typename TypeDescriptor::MainType<A,B>::type  MinMag (const A& a, const B& b)
	{
		if ( Abs(a) > Abs(b) )	return b;
		if ( Abs(a) < Abs(b) )	return a;
		return Min( a, b );
	}

	template <typename A, typename B, usize I>
	inline TVec< typename TypeDescriptor::MainType<A,B>::type, I >  MinMag (const TVec<A,I>& a, const TVec<B,I>& b)
	{
		TVec< typename TypeDescriptor::MainType<A,B>::type, I >	ret;
		FOR( i, ret )	ret[i] = MinMag( a[i], b[i] );
		return ret;
	}

	
	//
	// MaxMag
	//

	template <typename A, typename B>
	inline typename TypeDescriptor::MainType<A,B>::type  MaxMag (const A& a, const B& b)
	{
		if ( Abs(a) > Abs(b) )	return a;
		if ( Abs(a) < Abs(b) )	return b;
		return Max( a, b );
	}

	template <typename A, typename B, usize I>
	inline TVec< typename TypeDescriptor::MainType<A,B>::type, I >  MaxMag (const TVec<A,I>& a, const TVec<B,I>& b)
	{
		TVec< typename TypeDescriptor::MainType<A,B>::type, I >	ret;
		FOR( i, ret )	ret[i] = MaxMag( a[i], b[i] );
		return ret;
	}
	
	
	//
	// Mid
	//

	template <typename A, typename B, typename C>
	inline typename TypeDescriptor::MainType3<A,B,C>::type  Mid (const A& a, const B& b, const C& c)
	{
		return Min( Max( a, b ), Max( b, c ) );
	}

	template <typename A, typename B, typename C, usize I>
	inline TVec< typename TypeDescriptor::MainType3<A,B,C>::type, I >  Mid (const TVec<A,I>& a, const TVec<B,I>& b, const TVec<C,I>& c)
	{
		TVec< typename TypeDescriptor::MainType3<A,B,C>::type, I >	ret;
		FOR( i, ret )	ret[i] = Mid( a[i], b[i], c[i] );
		return ret;
	}
	

//-------------------------------------------------------------------
//	

	//
	// Static Pow
	//
	
	namespace _math_hidden_
	{
		template <int I>
		struct _TPowerStructUnsigned
		{
			template <typename T>	static T power(const T& x)		{ return _TPowerStructUnsigned<I-1>::power( x ) * x; }
		};
			
		template <>
		struct _TPowerStructUnsigned<0>
		{
			template <typename T>	static T power(const T& x)		{ return 1; }
		};

		
		template <bool S>
		struct _TPowerStruct
		{
			template <typename T, int I>
			static T power(const T& x)		{ return _TPowerStructUnsigned<I>::power( x ); }
		};

		template <>
		struct _TPowerStruct<true>
		{
			template <typename T, int I>
			static T power(const T& x)		{ return T(1) / _TPowerStructUnsigned<-I>::power( x ); }
		};
	}


	template <int I, typename T>
	inline T Pow(const T& x)
	{
		return _math_hidden_::_TPowerStruct< (I<0) >::template power<T,I>( x );
	}


	template <int P, typename T, usize I>
	inline TVec<T,I>  Pow(const TVec<T,I>& x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Pow<P>( x[i] );
		return ret;
	}



	//
	// Pow, Pow2, Pow10
	//

	template <typename T, typename B>
	inline T Pow(const T&x, const B& y)
	{
		typedef typename TypeDescriptor::MainType<T,B>::type		main_t;
		typedef typename _math_hidden_::ToNearFloat< main_t >::type	float_t;
		return ::_hidden_::pow( float_t( x ), float_t( y ) );
	}


	template <typename T, typename B, usize I>
	inline TVec<T,I>  Pow(const TVec<T,I>& x, const TVec<B,I>& y)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Pow( x[i], y[i] );
		return ret;
	}


	template <typename R, typename T>
	inline R Pow2(const int& p)
	{
		if ( p >= 0 )
			return R( T(1) << p );
		else
			return R(1) / R( T(1) << (-p) ); 
	}


	template <typename R, typename T, usize I>
	inline TVec<R,I>  Pow2(const TVec<int,I>& p)
	{
		TVec<R,I>	ret;
		FOR( i, ret )	ret[i] = Pow2<R,T>( p[i] );
		return ret;
	}


	template <typename R>
	inline R Pow2(const int& p)
	{
		return Pow2<R,int>( p );
	}


	template <typename R, usize I>
	inline TVec<R,I>  Pow2(const TVec<int,I>& p)
	{
		TVec<R,I>	ret;
		FOR( i, ret )	ret[i] = Pow2<R,int>( p[i] );
		return ret;
	}
	

	template <typename R>
	inline R  Pow10(const int p)
	{
		R	ret = R(1);

		for (int i = 0; i < Abs(p); ++i)
			ret *= R(10);

		return ( p < 0  ?  R(1) / ret  :  ret );
	}


	template <typename T, uint I>
	inline TVec<T,I>  Pow10(const TVec<int,I> &p)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Pow10<T>( p[i] );
		return ret;
	}

	

	//
	// Static Pow2
	//

	template <int P, typename R, typename T>
	constexpr
	inline R Pow2()
	{
		if ( P >= 0 )
			return R( T(1) << P );
		else
			return R(1) / R( T(1) << (-P) );
	}


	template <int P, typename R>
	constexpr
	inline R Pow2()
	{
		return Pow2<P,R,int>();
	}



	//
	// Ln, Log, Log2, Log10
	//

	template <typename T>
	inline T Ln(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::log( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Ln(const TVec<T,I>& x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Ln( x[i] );
		return ret;
	}


	template <uint Base, typename T>
	inline T Log(const T& x)
	{
		return Log( x, T( Base ) );
	}


	template <uint Base, typename T, usize I>
	inline TVec<T,I>  Log(const TVec<T,I>& x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Log<Base>( x[i] );
		return ret;
	}

	
	template <typename T>
	inline T  Log(const T& x, const T& base)
	{
		return Ln( x ) / Ln( base );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Log(const TVec<T,I>& x, const T& base)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Log( x[i], base );
		return ret;
	}


	template <typename T, usize I>
	inline TVec<T,I>  Log(const TVec<T,I>& x, const TVec<T,I>& base)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Log( x[i], base[i] );
		return ret;
	}


	template <typename T>
	inline T Log2(const T& x)
	{
		return Log<2>( x );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Log2(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Log<2>( x[i] );
		return ret;
	}


	template <typename T>
	inline T Log10(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::log10( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Log10(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Log10( x[i] );
		return ret;
	}



	//
	// Exp, Exp2, Exp10
	//

	template <typename T>
	inline T Exp(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::exp( float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Exp(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Exp( x[i] );
		return ret;
	}


	template <typename T>
	inline T Exp2(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::pow( float_t( 2 ), float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Exp2(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Exp2( x[i] );
		return ret;
	}
	

	template <typename T>
	inline T  Exp10(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::pow( float_t( 10 ), float_t( x ) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  Exp10(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Exp10( x[i] );
		return ret;
	}
	

	//
	// Power Of Two
	//

	namespace _math_hidden_
	{
		template <uint Bit>
		struct _RecursiveGetPOT
		{
			template <typename T>
			inline static uint Get (const T& x)
			{
				return uint( (x >> Bit) > 0 ) + _RecursiveGetPOT< Bit-1 >::Get( x );
			}
		};

		template <>
		struct _RecursiveGetPOT<0>
		{
			template <typename T>
			inline static uint Get (const T& x)
			{
				return uint( x > 0 );
			}
		};

	}	// _math_hidden_

	template <typename T>
	inline uint PowerOfTwo(const T& x)
	{
		TypeDescriptor::MustBeInteger<T>();

		typedef typename TypeInfo<T>::Similar_Unsigned	utype;

		const utype	value = ReferenceCast<utype>(x);

		return _math_hidden_::_RecursiveGetPOT< CompileTime::SizeOf< utype >::bits-1 >::Get( value );
	}


	template <typename T, usize I>
	inline TVec<uint,I>  PowerOfTwo(const TVec<T,I> &x)
	{
		TVec<uint,I>	ret;
		FOR( i, ret )	ret[i] = PowerOfTwo( x[i] );
		return ret;
	}

	
	template <typename T>
	inline T CeilPowerOfTwo(const T& x)
	{
		TypeDescriptor::MustBeInteger<T>();

		return ( T(1) << (PowerOfTwo(x) + 1) ) * Sign(x);
	}


	template <typename T, usize I>
	inline TVec<T,I>  CeilPowerOfTwo(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = CeilPowerOfTwo( x[i] );
		return ret;
	}

	
	template <typename T>
	inline T FloorPowerOfTwo(const T& x)
	{
		TypeDescriptor::MustBeInteger<T>();

		return ( T(1) << PowerOfTwo(x) ) * Sign(x);
	}


	template <typename T, usize I>
	inline TVec<T,I>  FloorPowerOfTwo(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = FloorPowerOfTwo( x[i] );
		return ret;
	}

	
	template <typename T>
	inline T NearPowerOfTwo(const T& x)
	{
		TypeDescriptor::MustBeInteger<T>();
		
		const T		absx	= Abs( x );
		const uint	pot		= PowerOfTwo( x );
		const T		a		= T(1) << (pot + 1);
		const T		b		= T(1) << pot;
		const T		c		= ((a - b) >> 1) + b;
		return ( absx >= c ? a : b ) * Sign( x );
	}


	template <typename T, usize I>
	inline TVec<T,I>  NearPowerOfTwo(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = NearPowerOfTwo( x[i] );
		return ret;
	}
	
	
	template <typename T>
	inline bool IsPowerOfTwo(const T& x)
	{
		TypeDescriptor::MustBeInteger<T>();
		
		const T	a = Abs( x );
		return ( a != 0 and ( (a & (a - 1)) == 0 ) );
	}


	template <typename T, usize I>
	inline TVec<bool,I>  IsPowerOfTwo(const TVec<T,I> &x)
	{
		TVec<bool,I>	ret;
		FOR( i, ret )	ret[i] = IsPowerOfTwo( x[i] );
		return ret;
	}



	//
	// Square
	//

	template <typename T>
	inline T Square(const T& x)
	{
		return x * x;
	}


	template <typename T, usize I>
	inline TVec<T,I>  Square(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Square( x[i] );
		return ret;
	}
	


	//
	// Sqrt
	//

	template <typename T>
	inline T Sqrt(const T& x)
	{
		ASSERT( IsZero( x ) or x > T(0) );
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::sqrt( float_t( x ) );
	}


#ifdef UX_FAST_MATH
	template <>
	inline float Sqrt(const float &x)
	{
		return FSqrt( x );
	}
#endif


	template <typename T, usize I>
	inline TVec<T,I>  Sqrt(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Sqrt( x[i] );
		return ret;
	}
	


	//
	// Inverse Sqrt
	//

	template <typename T>
	inline T InvSqrt(const T& x)
	{
		return T(1) / Sqrt( x );
	}


#ifdef UX_FAST_MATH
	template <>
	inline float InvSqrt(const float &x)
	{
		return FInvSqrt( x );
	}
#endif


	template <typename T, usize I>
	inline TVec<T,I>  InvSqrt(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = InvSqrt( x[i] );
		return ret;
	}

	

	//
	// Square Sign
	//

	template <typename T>
	inline T SquareSign(const T& x)
	{
		return ( x < T(0) ? -Square(x) : Square(x) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  SquareSign(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SquareSign( x[i] );
		return ret;
	}

	

//-------------------------------------------------------------------
//	Interpolation

	//
	// Mix, QMix, BiMix, TriMix
	//
	
	template <typename T>
	inline T GetInterpolation (const T& x, const T& y, const T& interpolated)
	{
		return (interpolated - x) / (y - x);
	}


	// linear interpolation
	template <typename T, typename B>
	inline T Mix(const T& x, const T& y, const B& a)
	{
		return T( a * (y - x) + x );
	}
	

	// quadratic interpolation
	template <typename T, typename B>
	inline T QMix(const T& x, const T& y, const T& z, const B& a)
	{
		const B		inv  = B(1) - a;
		const B		mul0 = inv * inv;
		const B		mul1 = B(2) * a * inv;

		return (T)( x * mul0 + y * mul1 + z * Square( a ) );
	}


	// bilinear interpolation
	template <typename T, typename B>
	inline T BiMix(const T v[4], const B& a)
	{
		return Mix( Mix( v[0], v[3], a[0] ), Mix( v[1], v[2], a[0] ), a[1] );
	}

	template <typename T, typename B>
	inline T BiMix(const T& v0, const T& v1, const T& v2, const T& v3, const B& a)
	{
		return Mix( Mix( v0, v3, a[0] ), Mix( v1, v2, a[0] ), a[1] );
	}


	template <typename T, typename B>
	inline T BiMix(const T& v0, const T& v1, const T& v2, const T& v3, const B& a0, const B& a1)
	{
		return Mix( Mix( v0, v3, a0 ), Mix( v1, v2, a0 ), a1 );
	}

	
	// trilinear interpolation
	template <typename T, typename B>
	inline T TriMix(const T v[8], const B& a)
	{
		return Mix( Mix( Mix( v[0], v[2], a[0] ), Mix( v[1], v[3], a[0] ), a[1] ),
					Mix( Mix( v[4], v[6], a[0] ), Mix( v[5], v[7], a[0] ), a[1] ),
					a[2] );
	}
	
	template <typename T, typename B>
	inline T TriMix(const T &v0, const T &v1, const T &v2, const T &v3, const T &v4,
					const T &v5, const T &v6, const T &v7, const B& a)
	{
		return Mix( Mix( Mix( v0, v2, a[0] ), Mix( v1, v3, a[0] ), a[1] ),
					Mix( Mix( v4, v6, a[0] ), Mix( v5, v7, a[0] ), a[1] ),
					a[2] );
	}
	  

	// cubic interpolation
	template <typename T>
	inline T CubicMix(const T& v0, const T& v1, const T& v2, const T& v3, const T& a)
	{
		return	((v3 - v2) - (v0 - v1)) * a * a * a +
				(v3 - v2) * a * a +
				(v2 - v0) * a +
				v1;
	}

	
//-------------------------------------------------------------------
//	Other


	//
	// Mod
	//

	namespace _math_hidden_
	{
		template <typename T, typename B>
		struct _ModMainType {
			typedef typename TypeDescriptor::MainType<T,B>::type	type;
		};

		template <bool bFloat, bool b32GE>
		struct _ModNearType
		{
			template <typename T, typename B>
			static typename _ModMainType<T,B>::type  Mod(const T& l, const B& r);
		};

		template <>
		struct _ModNearType<true,true>
		{
			template <typename T, typename B>
			static typename _ModMainType<T,B>::type  Mod(const T& l, const B& r)
			{
				typedef typename _ModMainType<T,B>::type	main_t;
				return ::_hidden_::fmod( main_t(l), main_t(r) );
			}
		};

		template <>
		struct _ModNearType<true,false>
		{
			template <typename T, typename B>
			static typename _ModMainType<T,B>::type  Mod(const T& l, const B& r)
			{
				return ::_hidden_::fmod( float(l), float(r) );
			}
		};
			
		template <>
		struct _ModNearType<false,true>
		{
			template <typename T, typename B>
			static typename _ModMainType<T,B>::type  Mod(const T& l, const B& r)
			{
				typedef typename _ModMainType<T,B>::type			main_t;
				typedef typename TypeInfo< main_t >::Similar_Float	float_t;
				return ::_hidden_::fmod( float_t(l), float_t(r) );
			}
		};

		template <>
		struct _ModNearType<false,false>
		{
			template <typename T, typename B>
			static typename _ModMainType<T,B>::type  Mod(const T& l, const B& r)
			{
				return ::_hidden_::fmod( float(l), float(r) );
			}
		};
		
		template <typename T, typename B>
		struct ModNearType
		{
			typedef typename _ModMainType<T,B>::type	main_t;

			static main_t  Mod(const T& l, const B& r)
			{
				return _ModNearType< not TypeDescriptor::IsInteger<T>::value, sizeof(main_t) >= 4 >::Mod( l, r );
			}
		};
	}


	template <typename A, typename B>
	inline typename TypeDescriptor::MainType<A,B>::type  Mod (const A& left, const B& right)
	{
		return _math_hidden_::ModNearType<A,B>::Mod( left, right );
	}


	template <typename T>
	inline T  Mod (const T& left, const T& right)
	{
		return _math_hidden_::ModNearType<T,T>::Mod( left, right );
	}


	template <typename A, typename B, usize I>
	inline TVec< typename TypeDescriptor::MainType<A,B>::type, I >  Mod (const TVec<A,I> &left, const TVec<B,I> &right)
	{
		TVec< typename TypeDescriptor::MainType<A,B>::type, I >	ret;
		FOR( i, ret )	ret[i] = Mod( left[i], right[i] );
		return ret;
	}



	//
	// Floor, Ceil, Fract
	//
	
	template <typename T>
	inline T  Floor(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::floor( float_t( x ) );
	}


	template <typename T, uint I>
	inline TVec<T,I>  Floor(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Floor( x[i] );
		return ret;
	}


	template <typename T>
	inline T  Ceil(const T& x)
	{
		typedef typename _math_hidden_::ToNearFloat<T>::type  float_t;
		return ::_hidden_::ceil( float_t( x ) );
	}


	template <typename T, uint I>
	inline TVec<T,I>  Ceil(const TVec<T,I>& x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Ceil( x[i] );
		return ret;
	}
	

	template <typename T>
	inline T  Fract(const T& x)
	{
		return x - Floor(x);
	}


	template <typename T, uint I>
	inline TVec<T,I>  Fract(const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = Fract( x[i] );
		return ret;
	}



	//
	// Round
	//
	
	namespace _math_hidden_
	{
		template <bool ResultIsInteger, bool ValueIsInteger>
		struct _TRound	// int to int, int to float
		{
			template <typename R, typename T>
			static inline R Round(const T& val)
			{
				return R( val );
			}
		};
		
		template <>
		struct _TRound< true, false >	// float to int
		{
			template <typename R, typename T>
			static inline R Round(const T& val)
			{
				return R( val + ( val > T(0) ? T(0.5) : T(-0.5) ) );
			}
		};
		
		template <>
		struct _TRound< false, false >	// float to float
		{
			template <typename R, typename T>
			static inline R Round(const T& val)
			{
				return (R) Floor( val + ( val > T(0) ? T(0.5) : T(-0.5) ) );
			}
		};

	}	// _math_hidden_


	template <typename R, typename T>
	inline R Round (const T& x)
	{
		return _math_hidden_::_TRound<	TypeDescriptor::IsInteger<R>::value,
										TypeDescriptor::IsInteger<T>::value >::template Round< R, T >( x );
	}

	/*
#ifdef __UX_FAST__
# ifdef COMPILER_MSVC
	template <>
	inline int Round<int,float>(const float& val) 
	{
		int		res;
		__asm {
			fld     val
			fistp   res
		}
		return res;
	}
# endif

	template <>
	inline int Round<int,double>(const double& val)
	{
		const double	ret = val + 6755399441055744.5;
		return reinterpret_cast<const int &>( ret );
	}
#endif	// __UX_FAST__
	*/


	template <typename R, typename T, usize I>
	inline TVec<R,I>  Round (const TVec<T,I> &x)
	{
		TVec<R,I>	ret;
		FOR( i, ret )	ret[i] = Round<R,T>( x[i] );
		return ret;
	}


	template <typename T>
	inline typename NearInt::Signed<T>::type  RoundToInt (const T& val)
	{
		return Round< typename NearInt::Signed<T>::type, T >( val );
	}


	template <typename T, usize I>
	inline TVec< typename NearInt::Signed<T>::type, I >  RoundToInt (const TVec<T,I> &x)
	{
		TVec< typename NearInt::Signed<T>::type, I >	ret;
		FOR( i, ret )	ret[i] = RoundToInt( x[i] );
		return ret;
	}



	//
	// IsNaN, IsInfinity, IsFinite
	//

	template <typename T, usize I>
	inline TVec<bool,I>  IsNaN (const TVec<T,I>& x)
	{
		TVec<bool,I>	ret;
		FOR( i, ret )	ret[i] = IsNaN( x[i] );
		return ret;
	}

	template <typename T, usize I>
	inline TVec<bool,I>  IsInfinity (const TVec<T,I>& x)
	{
		TVec<bool,I>	ret;
		FOR( i, ret )	ret[i] = IsInfinity( x[i] );
		return ret;
	}

	template <typename T, usize I>
	inline TVec<bool,I>  IsFinite (const TVec<T,I>& x)
	{
		TVec<bool,I>	ret;
		FOR( i, ret )	ret[i] = IsFinite( x[i] );
		return ret;
	}



	//
	// Safe Division
	//

	template <typename T>
	inline T SafeDiv(const T& left, const T& right, const T& defVal)
	{
		return IsNotZero(right) ? (left / right) : defVal;
	}


	template <typename T, usize I>
	inline TVec<T,I>  SafeDiv(const TVec<T,I> &left, const TVec<T,I> &right, const T& defVal)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SafeDiv( left[i], right[i], defVal );
		return ret;
	}



	//
	// Safe Left Bit Shift
	//
	
	template <typename T, typename B>
	inline T  SafeLeftBitShift (const T& x, const B& shift)
	{
		TypeDescriptor::MustBeInteger<T>();
		TypeDescriptor::MustBeInteger<B>();

		return x << ( uint(shift) & ( (sizeof(T) << 3) - 1 ) );
	}
	
	template <typename T, usize I, typename B>
	inline TVec<T,I>  SafeLeftBitShift (const TVec<T,I> &x, const TVec<B,I>& shift)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SafeLeftBitShift( x[i], shift[i] );
		return ret;
	}
	
	template <typename T, usize I, typename B>
	inline TVec<T,I>  SafeLeftBitShift (const TVec<T,I> &x, const B& shift)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SafeLeftBitShift( x[i], shift );
		return ret;
	}
	


	//
	// Safe Right Bit Shift
	//

	template <typename T, typename B>
	inline T  SafeRightBitShift (const T& x, const B& shift)
	{
		TypeDescriptor::MustBeInteger<T>();
		TypeDescriptor::MustBeInteger<B>();
		
		return x >> ( uint(shift) & ( (sizeof(T) << 3) - 1 ) );
	}
	
	template <typename T, usize I, typename B>
	inline TVec<T,I>  SafeRightBitShift (const TVec<T,I> &x, const TVec<B,I>& shift)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SafeRightBitShift( x[i], shift[i] );
		return ret;
	}
	
	template <typename T, usize I, typename B>
	inline TVec<T,I>  SafeRightBitShift (const TVec<T,I> &x, const B& shift)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = SafeLeftBitShift( x[i], shift );
		return ret;
	}
	


	//
	// Circular Bit Shift
	//

	namespace _math_hidden_
	{
		inline uint32 _BitRotateLeft (uint32 N, int S)
		{
			return ((N >> (~S)) >> 1) | (N << S);
		}

		inline uint32 _BitRotateRight (uint32 N, int S)
		{
			return ((N << (~S)) << 1) | (N >> S);
		}
	}

	template <typename T, typename B>
	inline T  BitRotateLeft (const T& x, const B& shift)
	{
		TypeDescriptor::MustBeInteger<T>();
		TypeDescriptor::MustBeInteger<B>();

		typedef NearInt::Unsigned<T>::type	Unsigned_t;

		return _math_hidden_::_BitRotateLeft( Unsigned_t(x), int(shift) );
	}

	template <typename T, usize I, typename B>
	inline T  BitRotateLeft (const TVec<T,I> &x, const TVec<B,I>& shift)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = BitRotateLeft( x[i], shift[i] );
		return ret;
	}


	template <typename T, typename B>
	inline T  BitRotateRight (const T& x, const B& shift)
	{
		TypeDescriptor::MustBeInteger<T>();
		TypeDescriptor::MustBeInteger<B>();

		typedef NearInt::Unsigned<T>::type	Unsigned_t;

		return _math_hidden_::_BitRotateRight( Unsigned_t(x), int(shift) );
	}

	template <typename T, usize I, typename B>
	inline T  BitRotateRight (const TVec<T,I> &x, const TVec<B,I>& shift)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = BitRotateLeft( x[i], shift[i] );
		return ret;
	}

	

	//
	// To Bit
	//

	template <typename T, typename B>
	inline T  ToBit (const B bitIndex)
	{
		return SafeLeftBitShift( T(1), bitIndex );
	}

	template <typename T, uint I, typename B>
	inline TVec<T,I>  ToBit (const TVec<B,I> &bitIndex)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ToBit<T>( bitIndex[i] );
		return ret;
	}

	
	//
	// To Mask
	//

	template <typename T, typename B>
	inline T  ToMask (const B bitIndex)
	{
		TypeDescriptor::MustBeInteger<T>();
		TypeDescriptor::MustBeInteger<B>();

		const uint	mask = (sizeof(T) << 3) - 1;

		return bitIndex > mask ? T(-1) : T( (T(1) << bitIndex) - 1 );
	}

	template <typename T, usize I, typename B>
	inline TVec<T,I>  ToMask (const TVec<B,I> bitIndex)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ToMask<T>( bitIndex[i] );
		return ret;
	}
	

	
	//
	// Get Bit Mask For Type
	//

	template <typename T>
	inline T  GetMaskForType (const T &)
	{
		TypeDescriptor::MustBeInteger<T>();
		return T(-1);
	}
	
	template <typename T, usize I>
	inline TVec<T,I>  GetMaskForType (const TVec<T,I> &)
	{
		return TVec<T,I>( GetMaskForType<T>() );
	}



	//
	// IsOdd, IsEven
	//

	// нечетный
	template <typename T>
	inline bool  IsOdd (const T& x)
	{
		TypeDescriptor::MustBeInteger<T>();
		return ( x & T(1) ) == T(1);
	}


	template <typename T, usize I>
	inline TVec<bool,I>  IsOdd (const TVec<T,I> &x)
	{
		TVec<bool,I>	ret;
		FOR( i, ret )	ret[i] = IsOdd( x[i] );
		return ret;
	}


	// четный
	template <typename T>
	inline bool  IsEven (const T& x)
	{
		TypeDescriptor::MustBeInteger<T>();
		return ( x & T(1) ) == T(0);
	}

	
	template <typename T, usize I>
	inline TVec<bool,I>  IsEven (const TVec<T,I> &x)
	{
		TVec<bool,I>	ret;
		FOR( i, ret )	ret[i] = IsEven( x[i] );
		return ret;
	}



	//
	// ToOdd, ToEven
	//

	template <typename T>
	inline T  ToOdd (const T &x)
	{
		TypeDescriptor::MustBeInteger<T>();
		return ( x | T(1) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ToOdd (const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ToOdd( x[i] );
		return ret;
	}


	template <typename T>
	inline T  ToEven (const T &x)
	{
		TypeDescriptor::MustBeInteger<T>();
		return ( x & ~T(1) );
	}


	template <typename T, usize I>
	inline TVec<T,I>  ToEven (const TVec<T,I> &x)
	{
		TVec<T,I>	ret;
		FOR( i, ret )	ret[i] = ToEven( x[i] );
		return ret;
	}

//-------------------------------------------------------------------

}	// UXMath
}	// UX_STL

#endif	// _UXS_MATH_H